//
//  SKBoard+Helper.m
//  Sudoku
//
//  Created by Richard Hodgkins on 29/09/2012.
//  Copyright (c) 2012 Richard Hodgkins. All rights reserved.
//

#import "SKBoard+Helper.h"

#import "SKBoardConstants.h"

#define SECS_IN_MILLIS 1000
#define MIN_IN_MILLIS (SECS_IN_MILLIS * 60)

#define ELAPSED_TIME_FORMAT @"%02ld:%02ld"

#define BOARD_ENDS @"-------------------------------------------\n"
#define BOARD_MIDDLE @"|-------------+-------------+-------------|\n"
#define BOARD_BOX_SEP @"| "
#define BOARD_BOX_END @"|\n"
#define BOARD_CELL_SEP @"  "
#define BOARD_CELL @"% hhd"
#define BOARD_CELL_SIZE 2

#define BOARD_DEBUG_ROW_COUNT (([BOARD_BOX_SEP length] * 3) + [BOARD_BOX_END length] + (CELLS_PER_ROW * ([BOARD_CELL_SEP length] + BOARD_CELL_SIZE)))
#define BOARD_DEBUG_PRINT_COUNT (1 + ([BOARD_ENDS length] * 2) + ([BOARD_MIDDLE length] * 2) + (BOARD_DEBUG_ROW_COUNT * CELLS_PER_COL))
/*
-------------------------------------------
|  1   2   3  |  4   5   6  |  7   8   9  |
|  2   3   4  |  5   6   7  |  8   9   1  |
|  3   4   5  |  6   7   8  |  9   1   2  |
|-------------+-------------+-------------|
|  4   5   6  |  7   8   9  |  1   2   3  |
|  5   6   7  |  8   9   1  |  2   3   4  |
|  6   7   8  |  9  -1   2  |  3   4   5  |
|-------------+-------------+-------------|
|  7   8   9  | -1   2   3  |  4   5   6  |
|  8   9  -1  |  2   3   4  |  5   6   7  |
|  9  -1   2  |  3   4   5  |  6   7   8  |
-------------------------------------------
*/

@implementation SKBoard (Helper)

-(NSString *) description
{
    return [NSString stringWithFormat:@"%@ [boardId=%d, name=%@, bestTime=%@, difficulty=%d, rating=%f, duration=%@, layout=%@, moves=%@", [self class], self.boardId, self.name, [self bestTimeString], self.difficulty, self.rating, [SKBoard stringForDuration:self.duration], [SKBoard stringForLayout:self.layout], [SKBoard stringForLayout:self.moves]];
}

- (NSInteger) completed
{
    const NSInteger score = lrint(self.duration * SECS_IN_MILLIS);
    DLog(@"Setting score: %d (old score %d)", score, self.bestScore);
    if (self.bestScore == -1 || score < self.bestScore) {
        self.bestScore = score;
    }
    // Clear the boards state as we no longer care as it's been completed
    self.moves = nil;
    self.duration = 0;
    
    return score;
}

- (NSString *) bestTimeString
{
    return [SKBoard stringForDuration:self.bestScore / 1000.0];
}

+ (NSString *) stringForLayout:(NSData *)layout
{
    if (!layout) {
        return nil;
    }
#ifdef DEBUG
    const SInt8 *board = (SInt8 *) layout.bytes;

    NSMutableString *str = [NSMutableString stringWithCapacity:BOARD_DEBUG_PRINT_COUNT];
    [str appendString:@"\n"];
    [str appendString:BOARD_ENDS];
    for (int i=0; i<BOX_ROWS; i++) {
        for (int j=0; j<BOX_COLS; j++) {
            for (int k=0; k<CELL_ROWS; k++) {
                [str appendString:BOARD_BOX_SEP];
                for (int l=0; l<CELL_COLS; l++) {
                    [str appendFormat:BOARD_CELL, *(board++)];
                    [str appendString:BOARD_CELL_SEP];
                }
            }
            [str appendString:BOARD_BOX_END];
        }
        if (i+1 < BOX_ROWS) {
            [str appendString:BOARD_MIDDLE];
        } else {
            [str appendString:BOARD_ENDS];
        }
    }
    return str;
#else
    return [layout description];
#endif
}

+ (NSString *) stringForDuration:(NSTimeInterval) duration
{
    if (duration > 0) {
        NSUInteger elapsedTime = rintl(duration * SECS_IN_MILLIS);
        
        long mins = elapsedTime / MIN_IN_MILLIS;
        long secs = rintl((NSTimeInterval) (elapsedTime - (mins * MIN_IN_MILLIS))) / SECS_IN_MILLIS;
        
        return [NSString stringWithFormat:ELAPSED_TIME_FORMAT, mins, secs];
    } else {
        return nil;
    }
}

+(NSFetchRequest *) fetchRequestInContext:(NSManagedObjectContext *)context
{
    NSFetchRequest *request = [super fetchRequestInContext:context];
    request.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:COL_SKBOARD_DIFFICULTY ascending:YES], [[NSSortDescriptor alloc] initWithKey:COL_SKBOARD_NAME ascending:YES]];
    return request;
}

+ (void) insertBoard:(NSInteger)boardId withName:(NSString *)name withDifficulty:(SKBoardDifficulty)difficulty withRating:(float)rating withLayout:(SInt8 *)layout
{    
    const SKBoard *board = [self insertNewInstance];
    
    board.boardId = boardId;
    board.name = name;
    board.difficulty = difficulty;
    board.rating = rating;
    board.layout = [NSData dataWithBytes:layout length:SIZE_OF_LAYOUT];
}

@end
